package wumpusworld;
import java.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;


/**
 * Contans starting code for creating your own Wumpus World agent.
 * Currently the agent only make a random decision each turn.
 * 
 * @author Johan Hagelbäck
 */
public class MyAgent implements Agent
{
	
    private World w;
    private KnowledgeMap myMap;
    
    private List<Integer> Action=new ArrayList<Integer>();
  
    
    /**
     * Creates a new instance of your solver agent.
     * 
     * @param world Current world state 
     */
    public MyAgent(World world)
    {
        w = world;
        myMap = new KnowledgeMap(w);
    }
    
    /**
     * Asks your solver agent to execute an action.
     */
    public void doAction()
    {  	

    	if (w.hasGold())
    	{
    		return;
    	}
        int cX = w.getPlayerX();
        int cY = w.getPlayerY();
        myMap.computePosition(cX, cY);
        
        //Basic action:
        //Grab Gold if we can.
        if (myMap.shouldIShoot(cX, cY) == 'n' && w.hasGlitter(cX, cY))
        {
        	w.doAction(World.A_GRAB);
            return;
        }
        
        //Basic action:
        //We are in a pit. Climb up.
        if (w.isInPit())
        {
        	Action.add(5);
        	w.doAction(World.A_CLIMB);Action.remove(0);
            return;
        }
    	// if the list of action is not empty, we do the next action
    	if(!(Action.isEmpty()))
        {
        	int a=Action.get(0);
        	switch(a)
        	{
        		case 0: w.doAction(World.A_TURN_LEFT); Action.remove(0); break;
        		case 1: w.doAction(World.A_TURN_RIGHT);Action.remove(0);break;
        		case 2: w.doAction(World.A_MOVE);Action.remove(0);break;
        		case 3: w.doAction(World.A_SHOOT);Action.remove(0);break;
        	}
        }
    	//else if it's empty we ask for the new action we sould do;
        else if(Action.isEmpty())
        {
        	generateAction();
        	int a=Action.get(0);
        	switch(a)
        	{
        		case 0: w.doAction(World.A_TURN_LEFT); Action.remove(0); break;
        		case 1: w.doAction(World.A_TURN_RIGHT);Action.remove(0);break;
        		case 2: w.doAction(World.A_MOVE);Action.remove(0);break;
        		case 3: w.doAction(World.A_SHOOT);Action.remove(0);break;
        	}
        }      
    }
    
    
    public void generateAction()
    {
        int cX = w.getPlayerX();
        int cY = w.getPlayerY();
        int Nx=cX;
        int Ny=cY;
        
    	char b =myMap.shouldIShoot(cX, cY);
    	
    	// Should we shoot an arrrow 
    	if(b!='n' && w.hasArrow())
    	{
    		if(b=='r')
    		{
        		faceRight(w.getDirection());
        		Action.add(3);
        		return;
    		}
    		if(b=='l')
    		{
        		faceLeft(w.getDirection());
        		Action.add(3);
        		return;
    		}
    		if(b=='t')
    		{
        		faceUp(w.getDirection());
        		Action.add(3);
        		return;
    		}
    		if(b=='b')
    		{
        		faceDown(w.getDirection());
        		Action.add(3);
        		return;
    		}
    		
    	}
    	

    	// if we don't have to shoot we ask the next targeted square
	    int[] target = myMap.getNextTarget(cX, cY);
	    
    	// if there is wumpus in all the possibility, we shoot an arrow and go further
	    if (target[0] == 0 && target[1] == 0)
	    {
	    	Action.add(3);
	    	Action.add(2);
	    	return;
	    }
	    
	    // otherwise we try to found a path to the targeted square
	    
	    int curDir = w.getDirection();
	    while(target[0]!=Nx || target[1]!=Ny)
	    {

	    	int N = 1;
	    	int UP[]=new int[2];
	   		int DOWN[]=new int[2];
	   		int LEFT[]=new int[2];
	  		int RIGHT[]=new int[2];
	  		
    		if(this.w.isValidPosition(Nx, Ny+1))
	    	{
	    		if(myMap.isSafe(Nx, Ny+1))
	    		{
	    			UP[0]=1;
	   				UP[1]=cost(Nx,Ny+1,target[0],target[1]);
	    		}
	    		else 
	    		{	
	    			if(myMap.hasPit(Nx, Ny+1))
	    			{
	    				UP[1]=cost(Nx,Ny+1,target[0],target[1]) *4;
	    			}
	    			else
	    			{
	    			UP[0]=1;
	   				UP[1]=cost(Nx,Ny+1,target[0],target[1]) *2;
	    			}
	    		}
	    	}
	    	else
	    	{
	    		UP[0]=0;
	   			UP[1]=999;
	   		}
    		
	   		if(this.w.isValidPosition(Nx, Ny-1))
	   		{
    			if(myMap.isSafe(Nx, Ny-1))
	   			{
	   				DOWN[0]=1;
	   				DOWN[1]=cost(Nx, Ny-1,target[0],target[1]);
	   			}
    			else
    			{
	    			if(myMap.hasPit(Nx, Ny-1))
	    			{	
	    				DOWN[0]=1;
	    				DOWN[1]=cost(Nx, Ny-1,target[0],target[1]) *4;
	    			}
	    			else
	    			{
	    				DOWN[0]=1;
	    				DOWN[1]=cost(Nx, Ny-1,target[0],target[1]) *2;
	    			}
    			}
    		}
	   		
	    	else
	    	{
	   			DOWN[0]=0;
	   			DOWN[1]=999;
	   		}
	   		
	   		if(this.w.isValidPosition(Nx+1, Ny))
    		{
	    		if(myMap.isSafe(Nx+1, Ny))
	    		{
	   				RIGHT[0]=1;
	   				RIGHT[1]=cost(Nx+1, Ny,target[0],target[1]);
	   			}
	    		else
	    		{
	    			if(myMap.hasPit(Nx+1, Ny))
	    			{
	    				RIGHT[0]=1;
	    				RIGHT[1]=cost(Nx+1, Ny,target[0],target[1]) *4;
	    			}
	    			else
	    			{
	    				RIGHT[0]=1;
	    				RIGHT[1]=cost(Nx+1, Ny,target[0],target[1]) *2;
	    			}
	    		}
	   		}
	    	else
	    	{
	   			RIGHT[0]=0;
	   			RIGHT[1]=999;
	   		}
	   	
	   		if(this.w.isValidPosition(Nx-1, Ny))
    		{
	    		if(myMap.isSafe(Nx-1, Ny))
	    		{
	    			LEFT[0]=1;
	   				LEFT[1]=cost(Nx-1, Ny,target[0],target[1]);
	   			}
	    		else
	    		{
	    			if(myMap.hasPit(Nx-1, Ny))
	    			{
	    				LEFT[0]=1;
	    				LEFT[1]=cost(Nx-1, Ny,target[0],target[1]) *4;
	    			}
	    			else
	    			{
	    				LEFT[0]=1;
	    				LEFT[1]=cost(Nx-1, Ny,target[0],target[1]) *2;
	    			}
	    		}
	   		}
	   		else
    		{
	    		LEFT[0]=0;
	    		LEFT[1]=999;
	    	}
	   			
	   		int currCost = 1000;
	   		if(DOWN[0] == 1 && currCost > DOWN[1])
	   		{	
    			currCost = DOWN[1];
	    		N=2;
	    	}

	    	if(LEFT[0] == 1 && currCost > LEFT[1])
	   		{
	   			currCost = LEFT[1];
	   			N=3;
	   		}
	    	
	    	if(RIGHT[0] == 1 && currCost > RIGHT[1])
	    	{
	   			currCost = RIGHT[1];
	   			N=1;
	   		}
	    	
	   		if(UP[0] == 1 && currCost > UP[1])
    		{	
	    		N=0;
	    	}

	   		switch(N)
	   		{
	    		case 0: faceUp(curDir);curDir = 0;Action.add(2);Ny++;break;
	    		case 3: faceLeft(curDir);curDir = 3;Action.add(2);Nx--;break;
		    	case 2: faceDown(curDir);curDir = 2;Action.add(2);Ny--;break;
		    	case 1: faceRight(curDir);curDir = 1;Action.add(2);Nx++;break;
	    	}
	   	}	
    }
    	
    public int cost(int x, int y, int tx, int ty)
    {
        int m = Math.abs(x - tx);
        int n = Math.abs(y - ty);
    	
    	return  m+n;
    }
    
    
    public void faceUp(int d)
    {
    	switch(d)
    	{
	    	case 0: break;
	    	case 1: Action.add(0);break;
	    	case 2: Action.add(0);Action.add(0);break;
	    	case 3: Action.add(1);break;
    	}
    }
    public void faceDown(int d)
    {
    	switch(d)
    	{
	    	case 0: Action.add(0);Action.add(0);break;
	    	case 1: Action.add(1);break;
	    	case 2: break;
	    	case 3: Action.add(0);break;
    	}
    }
    public void faceRight(int d)
    {
    	switch(d)
    	{
	    	case 0: Action.add(1);break;
	    	case 1: break;
	    	case 2: Action.add(0);break;
	    	case 3: Action.add(1);Action.add(1);break;
    	}
    }
    public void faceLeft(int d)
    {
    	switch(d)
    	{
	    	case 0: Action.add(0);break;
	    	case 1: Action.add(0);Action.add(0);break;
	    	case 2: Action.add(1);break;
	    	case 3: break;
    	}
    }
}
